using System.Text;

namespace TPXSDK.NET.UObject;

/// <summary>
/// UAV Object对象基类
/// </summary>
public class UObjBase
{
    private UObjMeta _meta = new();

    /// <summary>
    /// Meta元数据描述结构
    /// </summary>
    public UObjMeta Meta
    {
        get => _meta;
        internal set
        {
            _meta = value;
            Size = 0;
            for (var i = 0; i < _meta.MemCnt; i++)
            {
                Size += _meta.MemSize(i);
            }

            Member = [];
            foreach (var nm in _meta.MemName)
            {
                Member.Add(nm, null);
            }
        }
    }

    /// <summary>
    /// 结构对象大小，单位字节
    /// </summary>
    public int Size { get; private set; }

    /// <summary>
    /// 是否为参数对象
    /// </summary>
    public bool IsSetting => Meta?.IsSetting ?? false;

    /// <summary>
    /// 成员变量数组[通过成员名称访问]
    /// 注意字典表并不排序，不能通过整形索引获得成员
    /// </summary>
    public Dictionary<string, decimal?> Member { get; private set; } = [];

    /// <summary>
    /// 通过名称索引获得和设置UObject对象
    /// </summary>
    public decimal? this[string memName]
    {
        get => Member[memName];
        set => Member[memName] = value;
    }

    /// <summary>
    /// 根据Member Name获得对应单位字符串
    /// </summary>
    private string GetMemUnit(string memName)
    {
        var index = Array.IndexOf(Meta.MemName, memName);
        if (index >= 0)
        {
            return Meta.MemUnit[index];
        }
        return string.Empty;
    }

    /// <summary>
    /// 将当前对象详细信息转换为字符串
    /// </summary>
    public string DumpToStr()
    {
        var sb = new StringBuilder();
        foreach (var (k, v) in Member)
        {
            var strUnit = GetMemUnit(k);
            if (string.IsNullOrEmpty(strUnit))
            {
                sb.AppendLine($"{this}.{k}={v}");
            }
            else
            {
                var expression = $"{this}.{k}={v}";
                sb.AppendLine($"{expression,-32}//{strUnit}");
            }
        }
        return sb.ToString();
    }

    /// <summary>
    /// 根据Meta信息将Members值转换为字节数组，失败返回null
    /// </summary>
    public byte[]? MemberToBytes(int memIndex)
    {
        var val = Member[_meta.MemName[memIndex]];
        var data = Meta.MemType[memIndex] switch
        {
            MetaDataType.DT_U8 => [Convert.ToByte(val)],
            MetaDataType.DT_S8 => [(byte)Convert.ToSByte(val)],
            MetaDataType.DT_U16 => BitConverter.GetBytes(Convert.ToUInt16(val)),
            MetaDataType.DT_S16 => BitConverter.GetBytes(Convert.ToInt16(val)),
            MetaDataType.DT_U32 => BitConverter.GetBytes(Convert.ToUInt32(val)),
            MetaDataType.DT_S32 => BitConverter.GetBytes(Convert.ToInt32(val)),
            MetaDataType.DT_FP32 => BitConverter.GetBytes(Convert.ToSingle(val)),
            _ => null
        };

        return data;
    }

    /// <summary>
    /// 根据Meta信息通过字节数组更新Members值，返回更新使用字节大小
    /// </summary>
    public int MemberUpdate(int memIndex, byte[] data, int oft)
    {
        try
        {
            decimal? valObj = Meta.MemType[memIndex] switch
            {
                MetaDataType.DT_U8 => data[oft],
                MetaDataType.DT_S8 => (sbyte)data[oft],
                MetaDataType.DT_U16 => BitConverter.ToUInt16(data, oft),
                MetaDataType.DT_S16 => BitConverter.ToInt16(data, oft),
                MetaDataType.DT_U32 => BitConverter.ToUInt32(data, oft),
                MetaDataType.DT_S32 => BitConverter.ToInt32(data, oft),
                MetaDataType.DT_FP32 => (decimal)BitConverter.ToSingle(data, oft),
                _ => null
            };

            Member[_meta.MemName[memIndex]] = valObj;
        }
        catch
        {
            Member[_meta.MemName[memIndex]] = null;
        }

        return _meta.MemSize(memIndex);
    }

    public int MemberUpdate(int memIndex, object val)
    {
        try
        {
            decimal? res = Meta.MemType[memIndex] switch
            {
                MetaDataType.DT_U8 => Convert.ToByte(val),
                MetaDataType.DT_S8 => Convert.ToSByte(val),
                MetaDataType.DT_U16 => Convert.ToUInt16(val),
                MetaDataType.DT_S16 => Convert.ToInt16(val),
                MetaDataType.DT_U32 => Convert.ToUInt32(val),
                MetaDataType.DT_S32 => Convert.ToInt32(val),
                MetaDataType.DT_FP32 => (decimal)Convert.ToSingle(val),
                _ => null
            };

            Member[_meta.MemName[memIndex]] = res;
        }
        catch
        {
            Member[_meta.MemName[memIndex]] = null;
        }

        return _meta.MemSize(memIndex);
    }

    #region 基于字节流读写操作
    /// <summary>
    /// UObj对象转换为字节数组
    /// </summary>
    public byte[]? ToBytes()
    {
        if (null == _meta || null == Member || Member.Count == 0)
        {
            return null;
        }

        var data = new List<byte>();
        for (var i = 0; i < _meta.MemCnt; i++)
        {
            var b = MemberToBytes(i);
            if (null == b) return null;

            data.AddRange(b);
        }
        return data.ToArray();
    }

    /// <summary>
    /// 将字节数组更新UObj对象
    /// </summary>
    public bool Update(byte[]? data, int oft)
    {
        if (null == data) return false;

        var totalSz = 0;
        for (var i = 0; i < _meta.MemCnt; i++)
        {
            totalSz += MemberUpdate(i, data, oft + totalSz);
        }
        return totalSz == Size;
    }
    #endregion

    #region 内部数据结构读写操作(Object模式)
    /// <summary>
    /// 值设置接口函数（Object对象）
    /// </summary>
    /// <returns>操作是否成功</returns>
    public bool SetValue(byte memId, object newVal)
    {
        if (!IsValueType(newVal))
        {
            return false;
        }

        if (memId > 0 && memId < Meta.MemCnt + 1)
        {
            return MemberUpdate(memId - 1, newVal) > 0;
        }

        return false;
    }

    /// <summary>
    /// 值设置接口函数（Object对象）
    /// </summary>
    /// <param name="uobj">待更新对象值</param>
    /// <returns>操作是否成功</returns>
    public bool SetValue(UObjBase uobj)
    {
        return Update(uobj.ToBytes(), 0);
    }

    /// <summary>
    /// 值读取接口函数（Object对象）
    /// </summary>
    /// <param name="memId">成员编码，0代表整个对象</param>
    /// <param name="valObj">数值对象</param>
    /// <returns>读取长度</returns>
    public int GetValue(byte memId, out object? valObj)
    {
        if (memId == 0)
        {
            throw new Exception("Not Support Whole Obj get!");
        }

        if (memId > Meta.MemCnt)
        {
            throw new Exception("Invalid Member ID!");
        }

        valObj = Member[_meta.MemName[memId - 1]];
        return _meta.MemSize(memId - 1);
    }
    #endregion

    /// <summary>
    /// 实例对象编码
    /// </summary>
    public int InstId { get; set; }

    /// <summary>
    /// 无效FieldID编码
    /// </summary>
    public const uint InvalidFieldId = 0xFFFFFFFF;

    /// <summary>
    /// 成员变量类型字符串
    /// </summary>
    public string MemType(string memName)
    {
        var index = Array.IndexOf(Meta.MemName, memName);
        return index < 0 ? "Unknown MemType" : $"{Meta.MemType[index]}";
    }

    /// <summary>
    /// 成员变量ID编码
    /// </summary>
    public byte MemId(string memName)
    {
        var index = Array.IndexOf(Meta.MemName, memName);
        if (index < 0) return 0xFF;
        return (byte)(index + 1);
    }

    public override string ToString()
    {
        return Meta.InstCnt > 1 ? $"{Meta.TypeName}[{InstId}]" : Meta.TypeName;
    }

    /// <summary>
    /// 用于判断该对象是否为值类型
    /// </summary>
    public static bool IsValueType(object valObj)
    {
        return valObj switch
        {
            uint or int or ushort or short or byte or sbyte or float => true,
            _ => valObj is string s && double.TryParse(s, out _),
        };
    }
}
